<template>
  <div
    class="canvas"
    ref="canvasRef"
    @dragover.prevent
    @drop="onDrop"
    @mousedown="onCanvasMouseDown"
    @wheel.prevent="onCanvasWheel"
  >
    <div
      class="canvas-content"
      :style="canvasTransformStyle"
      @mousedown="onContentMouseDown"
    >
      <!-- 渲染连线 -->
      <svg class="canvas-svg" :width="canvasWidth" :height="canvasHeight" @mousedown="onContentMouseDown">
        <template v-for="conn in connections">
          <!-- 透明的点击区域，用于选择连接线 -->
          <line
            :x1="getNodeCenter(conn.from).x"
            :y1="getNodeCenter(conn.from).y"
            :x2="getNodeCenter(conn.to).x"
            :y2="getNodeCenter(conn.to).y"
            stroke="transparent"
            stroke-width="15"
            class="connection-hitbox"
            @click="selectConnection(conn)"
          />
          <line
            :x1="getNodeCenter(conn.from).x"
            :y1="getNodeCenter(conn.from).y"
            :x2="getNodeCenter(conn.to).x"
            :y2="getNodeCenter(conn.to).y"
            stroke="#1890ff"
            stroke-width="3"
            marker-end="url(#arrowhead)"
            class="connection-line"
            :class="{ selected: selectedConnection?.id === conn.id }"
          />
          <!-- 连接线删除按钮 -->
          <circle
            v-if="selectedConnection?.id === conn.id"
            :cx="getConnectionCenter(conn).x"
            :cy="getConnectionCenter(conn).y"
            r="8"
            fill="#ff4d4f"
            stroke="#fff"
            stroke-width="2"
            class="connection-delete-btn"
            @click="deleteConnection(conn)"
            title="删除连接线"
          />
          <text
            v-if="selectedConnection?.id === conn.id"
            :x="getConnectionCenter(conn).x"
            :y="getConnectionCenter(conn).y + 3"
            text-anchor="middle"
            fill="#fff"
            font-size="12"
            font-weight="bold"
            class="connection-delete-text"
            @click="deleteConnection(conn)"
          >×</text>
        </template>
        
        <!-- 正在创建的连线 -->
        <line
          v-if="isConnecting"
          :x1="connectionStart.x"
          :y1="connectionStart.y"
          :x2="connectionEnd.x"
          :y2="connectionEnd.y"
          stroke="#ff4d4f"
          stroke-width="2"
          stroke-dasharray="5,5"
          marker-end="url(#arrowhead-dashed)"
        />
        
        <defs>
          <marker id="arrowhead" markerWidth="10" markerHeight="7" refX="9" refY="3.5" orient="auto">
            <polygon points="0 0, 10 3.5, 0 7" fill="#1890ff" />
          </marker>
          <marker id="arrowhead-dashed" markerWidth="10" markerHeight="7" refX="9" refY="3.5" orient="auto">
            <polygon points="0 0, 10 3.5, 0 7" fill="#ff4d4f" />
          </marker>
        </defs>
      </svg>
      <!-- 渲染节点 -->
      <div
        v-for="node in nodes"
        :key="node.id"
        class="canvas-node"
        :style="getNodeStyle(node)"
        @mousedown.stop="onNodeMouseDown(node, $event)"
        @click.stop="onSelectNode(node)"
      >
        <div>{{ node.name }}</div>
        <div class="node-type">{{ node.type }}</div>
        <div class="node-role">{{ node.role }}</div>
        
        <!-- 连接点 -->
        <div class="connection-points">
          <div 
            class="connection-point connection-point-out"
            @mousedown.stop="startConnection(node, $event)"
            title="点击开始连线"
          >
            <span class="connection-label">→</span>
          </div>
          <div 
            class="connection-point connection-point-in"
            :class="{ connecting: isConnecting && connectingFromNode?.id !== node.id }"
            @mousedown.stop="endConnection(node, $event)"
            :title="isConnecting && connectingFromNode?.id !== node.id ? '点击完成连线' : '点击完成连线'"
          >
            <span class="connection-label">←</span>
          </div>
        </div>
        
        <el-button size="small" type="danger" @click.stop="onDeleteNode(node.id)" style="margin-top: 4px;">删除</el-button>
      </div>
      
      <!-- 连线提示 -->
      <div v-if="isConnecting" class="connection-hint">
        正在创建连线，点击目标节点的蓝色连接点完成连接，或按ESC取消
      </div>
    </div>
    <!-- 缩放控件 -->
    <div class="canvas-zoom-controls">
      <el-button size="small" @click="zoomOut">-</el-button>
      <span class="zoom-label">{{ Math.round(scale * 100) }}%</span>
      <el-button size="small" @click="zoomIn">+</el-button>
      <el-button size="small" @click="resetTransform">重置</el-button>
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref, reactive, computed, onMounted, watch, nextTick } from 'vue'
import type { CSSProperties } from 'vue'

interface Node {
  id: string | number
  name: string
  type: string
  role: string
  x: number
  y: number
}

interface Connection {
  id: string | number
  from: string | number
  to: string | number
}

const props = defineProps<{
  nodes: Node[]
  connections: Connection[]
  width?: number
  height?: number
}>()

const emit = defineEmits<{
  'update:nodes': [nodes: Node[]]
  'update:connections': [connections: Connection[]]
  'selectNode': [node: Node]
}>()

const canvasRef = ref()

// 连线状态
const isConnecting = ref(false)
const connectionStart = reactive({ x: 0, y: 0 })
const connectionEnd = reactive({ x: 0, y: 0 })
const connectingFromNode = ref<Node | null>(null)
const selectedConnection = ref<Connection | null>(null)

// 画布缩放与平移
const scale = ref(1)
const offsetX = ref(0)
const offsetY = ref(0)
const minScale = 0.3
const maxScale = 2
const canvasWidth = 2000
const canvasHeight = 1600

const canvasTransformStyle = computed<CSSProperties>(() => ({
  transform: `translate(${offsetX.value}px, ${offsetY.value}px) scale(${scale.value})`,
  transformOrigin: '0 0',
  width: canvasWidth + 'px',
  height: canvasHeight + 'px',
  position: 'relative' as CSSProperties['position'],
}))

let isPanning = false
let panStart = { x: 0, y: 0 }
let panOrigin = { x: 0, y: 0 }
const isSpacePanning = ref(false)

function onGlobalKeyDown(e: KeyboardEvent) {
  if (e.code === 'Space') {
    isSpacePanning.value = true
    document.body.style.cursor = 'grab'
  }
}
function onGlobalKeyUp(e: KeyboardEvent) {
  if (e.code === 'Space') {
    isSpacePanning.value = false
    document.body.style.cursor = ''
  }
}
onMounted(() => {
  window.addEventListener('keydown', onGlobalKeyDown)
  window.addEventListener('keyup', onGlobalKeyUp)
})

function onDrop(e: DragEvent) {
  const nodeType = e.dataTransfer?.getData('nodeType')
  if (nodeType) {
    const node = JSON.parse(nodeType)
    const rect = canvasRef.value.getBoundingClientRect()
    const x = e.clientX - rect.left
    const y = e.clientY - rect.top
    const id = Date.now() + Math.random()
    emit('update:nodes', [...props.nodes, { ...node, id, x, y }])
  }
}

function onCanvasMouseDown(e: MouseEvent) {
  // 如果正在连线，点击空白区域取消连线
  if (isConnecting.value) {
    cancelConnection()
  }
  
  // 点击空白区域取消选择连接线
  const target = e.target as HTMLElement
  if (target.classList.contains('canvas') || target.classList.contains('canvas-svg')) {
    selectedConnection.value = null
  }
}

function onKeyDown(e: KeyboardEvent) {
  // ESC键取消连线
  if (e.key === 'Escape' && isConnecting.value) {
    cancelConnection()
  }
}

function getNodeStyle(node: Node) {
  return {
    position: 'absolute' as const,
    left: node.x + 'px',
    top: node.y + 'px',
    minWidth: '100px',
    background: '#fff',
    border: '1px solid #1890ff',
    borderRadius: '8px',
    padding: '10px 16px',
    boxShadow: '0 2px 8px #f0f1f3',
    cursor: 'move' as const,
    zIndex: 2,
  }
}

function getNodeCenter(id: string | number) {
  const node = props.nodes.find((n: Node) => n.id === id)
  if (!node) return { x: 0, y: 0 }
  // 调整连接点位置，确保在节点边缘
  return { x: node.x + 100, y: node.y + 30 }
}

function startConnection(node: Node, e: MouseEvent) {
  e.stopPropagation()
  console.log('startConnection called', { node })
  
  isConnecting.value = true
  connectingFromNode.value = node
  
  const rect = canvasRef.value.getBoundingClientRect()
  const nodeCenter = getNodeCenter(node.id)
  connectionStart.x = nodeCenter.x
  connectionStart.y = nodeCenter.y
  connectionEnd.x = e.clientX - rect.left
  connectionEnd.y = e.clientY - rect.top
  
  console.log('Connection started', {
    isConnecting: isConnecting.value,
    connectingFromNode: connectingFromNode.value,
    connectionStart,
    connectionEnd
  })
  
  // 添加鼠标移动监听和键盘监听
  window.addEventListener('mousemove', onMouseMove)
  window.addEventListener('mouseup', onMouseUp)
  window.addEventListener('keydown', onKeyDown)
}

function onMouseMove(e: MouseEvent) {
  if (!isConnecting.value) return
  
  const rect = canvasRef.value.getBoundingClientRect()
  connectionEnd.x = e.clientX - rect.left
  connectionEnd.y = e.clientY - rect.top
}

function onMouseUp(e: MouseEvent) {
  if (!isConnecting.value) return
  
  // 检查是否点击到了连接点
  const target = e.target as HTMLElement
  if (target.classList.contains('connection-point-in')) {
    // 如果点击的是输入连接点，不要取消连线
    return
  }
  
  window.removeEventListener('mousemove', onMouseMove)
  window.removeEventListener('mouseup', onMouseUp)
  window.removeEventListener('keydown', onKeyDown)
  
  // 点击空白区域，取消连线
  cancelConnection()
}

function endConnection(targetNode: Node, e: MouseEvent) {
  e.stopPropagation()
  
  console.log('endConnection called', {
    isConnecting: isConnecting.value,
    connectingFromNode: connectingFromNode.value,
    targetNode: targetNode
  })
  
  if (!isConnecting.value || !connectingFromNode.value) {
    console.log('Not connecting or no from node')
    return
  }
  
  // 检查是否连接到自己
  if (connectingFromNode.value.id === targetNode.id) {
    console.log('Cannot connect to self')
    cancelConnection()
    return
  }
  
  // 检查是否已经存在相同的连线
  const existingConnection = props.connections.find(
    (conn: Connection) => conn.from === connectingFromNode.value!.id && conn.to === targetNode.id
  )
  
  if (existingConnection) {
    console.log('Connection already exists')
    cancelConnection()
    return
  }
  
  // 创建新连线
  const newConnection: Connection = {
    id: Date.now() + Math.random(),
    from: connectingFromNode.value.id,
    to: targetNode.id
  }
  
  console.log('Creating new connection:', newConnection)
  emit('update:connections', [...props.connections, newConnection])
  
  // 清理事件监听器
  window.removeEventListener('mousemove', onMouseMove)
  window.removeEventListener('mouseup', onMouseUp)
  window.removeEventListener('keydown', onKeyDown)
  
  // 重置连线状态
  isConnecting.value = false
  connectingFromNode.value = null
  connectionStart.x = 0
  connectionStart.y = 0
  connectionEnd.x = 0
  connectionEnd.y = 0
}

function cancelConnection() {
  isConnecting.value = false
  connectingFromNode.value = null
  connectionStart.x = 0
  connectionStart.y = 0
  connectionEnd.x = 0
  connectionEnd.y = 0
  
  // 移除事件监听
  window.removeEventListener('mousemove', onMouseMove)
  window.removeEventListener('mouseup', onMouseUp)
  window.removeEventListener('keydown', onKeyDown)
}

function onNodeMouseDown(node: Node, e: MouseEvent) {
  // 按住空格时不拖动节点，优先平移画布
  if (isSpacePanning.value) return
  const startX = e.clientX
  const startY = e.clientY
  const origX = node.x
  const origY = node.y
  function onMouseMove(ev: MouseEvent) {
    const dx = ev.clientX - startX
    const dy = ev.clientY - startY
    node.x = origX + dx
    node.y = origY + dy
    emit('update:nodes', [...props.nodes])
  }
  function onMouseUp() {
    window.removeEventListener('mousemove', onMouseMove)
    window.removeEventListener('mouseup', onMouseUp)
  }
  window.addEventListener('mousemove', onMouseMove)
  window.addEventListener('mouseup', onMouseUp)
}

function onDeleteNode(id: string | number) {
  emit('update:nodes', props.nodes.filter((n: Node) => n.id !== id))
  emit('update:connections', props.connections.filter((c: Connection) => c.from !== id && c.to !== id))
}

function onSelectNode(node: Node) {
  emit('selectNode', node)
}

function getConnectionCenter(connection: Connection) {
  const fromCenter = getNodeCenter(connection.from)
  const toCenter = getNodeCenter(connection.to)
  return {
    x: (fromCenter.x + toCenter.x) / 2,
    y: (fromCenter.y + toCenter.y) / 2
  }
}

function selectConnection(connection: Connection) {
  selectedConnection.value = connection
}

function deleteConnection(connection: Connection) {
  if (confirm('确定要删除这条连接线吗？')) {
    emit('update:connections', props.connections.filter((c: Connection) => c.id !== connection.id))
    selectedConnection.value = null
  }
}

function onContentMouseDown(e: MouseEvent) {
  // 空格键按下时，任何区域都可平移
  if (isSpacePanning.value || e.target === e.currentTarget) {
    isPanning = true
    panStart = { x: e.clientX, y: e.clientY }
    panOrigin = { x: offsetX.value, y: offsetY.value }
    window.addEventListener('mousemove', onPanMove)
    window.addEventListener('mouseup', onPanEnd)
    e.preventDefault()
    return
  }
  // 否则只允许空白区域拖动
  if (e.target !== e.currentTarget) return
}
function onPanMove(e: MouseEvent) {
  if (!isPanning) return
  offsetX.value = panOrigin.x + (e.clientX - panStart.x)
  offsetY.value = panOrigin.y + (e.clientY - panStart.y)
}
function onPanEnd() {
  isPanning = false
  window.removeEventListener('mousemove', onPanMove)
  window.removeEventListener('mouseup', onPanEnd)
}

function onCanvasWheel(e: WheelEvent) {
  // 支持缩放，缩放中心为鼠标位置
  const delta = e.deltaY < 0 ? 1.1 : 0.9
  let newScale = scale.value * delta
  newScale = Math.max(minScale, Math.min(maxScale, newScale))
  // 缩放中心点坐标
  const rect = canvasRef.value.getBoundingClientRect()
  const mouseX = e.clientX - rect.left - offsetX.value
  const mouseY = e.clientY - rect.top - offsetY.value
  // 缩放时调整偏移量，保证鼠标指向不变
  offsetX.value = mouseX - (mouseX / scale.value) * newScale
  offsetY.value = mouseY - (mouseY / scale.value) * newScale
  scale.value = newScale
}
function zoomIn() {
  scale.value = Math.min(maxScale, scale.value + 0.1)
}
function zoomOut() {
  scale.value = Math.max(minScale, scale.value - 0.1)
}
function resetTransform() {
  scale.value = 1
  offsetX.value = 0
  offsetY.value = 0
}
</script>

<style scoped>
.canvas {
  position: relative;
  width: 100%;
  height: 100%;
  min-width: 1200px;
  min-height: 800px;
  background: #f7f8fa;
  border: 1px solid #e0e0e0;
  border-radius: 10px;
  box-shadow: 0 2px 8px #f0f1f3;
  overflow: auto;
}
.canvas-content {
  position: relative;
  width: 2000px;
  height: 1600px;
  user-select: none;
}
.canvas-svg {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  z-index: 1;
  pointer-events: auto;
}

.connection-line {
  cursor: pointer;
  transition: all 0.2s;
}

.connection-line:hover {
  stroke: #ff4d4f;
  stroke-width: 3;
}

.connection-line.selected {
  stroke: #ff4d4f;
  stroke-width: 3;
}

.connection-hitbox {
  cursor: pointer;
}

.connection-delete-btn {
  cursor: pointer;
  transition: all 0.2s;
  opacity: 1;
  z-index: 20;
}

.connection-delete-text {
  cursor: pointer;
  pointer-events: none;
  opacity: 1;
  transition: all 0.2s;
  z-index: 20;
}

.connection-delete-btn:hover {
  transform: scale(1.2);
}

.canvas-node {
  z-index: 5;
  position: relative;
}

.node-type {
  font-size: 12px;
  color: #888;
}

.node-role {
  font-size: 12px;
  color: #888;
}

.connection-points {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  pointer-events: none;
}

.connection-point {
  width: 16px;
  height: 16px;
  border-radius: 50%;
  cursor: pointer;
  transition: all 0.2s;
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  pointer-events: auto;
  z-index: 10;
  border: 2px solid #fff;
}

.connection-point-out {
  background: #52c41a;
  box-shadow: 0 0 0 2px #52c41a;
  right: -8px;
}

.connection-point-in {
  background: #1890ff;
  box-shadow: 0 0 0 2px #1890ff;
  left: -8px;
}

.connection-point:hover {
  transform: translateY(-50%) scale(1.2);
  box-shadow: 0 0 0 3px rgba(24, 144, 255, 0.3);
}

.connection-point-out:hover {
  background: #73d13d;
  box-shadow: 0 0 0 3px rgba(82, 196, 26, 0.3);
}

.connection-point-in:hover {
  background: #40a9ff;
  box-shadow: 0 0 0 3px rgba(24, 144, 255, 0.3);
}

/* 连线状态下的连接点样式 */
.connection-point-in.connecting {
  background: #ff4d4f;
  box-shadow: 0 0 0 3px rgba(255, 77, 79, 0.5);
  animation: pulse-connecting 1s infinite;
}

@keyframes pulse-connecting {
  0% { transform: translateY(-50%) scale(1); }
  50% { transform: translateY(-50%) scale(1.2); }
  100% { transform: translateY(-50%) scale(1); }
}

.connection-label {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  font-size: 10px;
  color: white;
  font-weight: bold;
  pointer-events: none;
}

.connection-hint {
  position: absolute;
  top: 20px;
  left: 50%;
  transform: translateX(-50%);
  background: #ff4d4f;
  color: white;
  padding: 8px 16px;
  border-radius: 4px;
  font-size: 14px;
  z-index: 10;
  animation: pulse 1.5s infinite;
}

@keyframes pulse {
  0% { opacity: 1; }
  50% { opacity: 0.7; }
  100% { opacity: 1; }
}
.canvas-zoom-controls {
  position: absolute;
  right: 24px;
  bottom: 24px;
  z-index: 20;
  background: rgba(255,255,255,0.95);
  border-radius: 8px;
  box-shadow: 0 2px 8px #f0f1f3;
  padding: 8px 12px;
  display: flex;
  align-items: center;
  gap: 8px;
}
.zoom-label {
  min-width: 48px;
  text-align: center;
  font-weight: bold;
  color: #1890ff;
}
</style> 